/**
 * @example
  @Injectable('configService')
  class ConfigService {
    public configValue: string = 'initialValue'
  }

  class Application {
    @Inject('configService')
    private configService: ConfigService

    public printConfig() {
      console.log(this.configService.configValue)
    }

    public updateConfig(newConfig: string) {
      this.configService.configValue = 'test'
    }
  }
 */

import { AppStore } from "./types/store"

// 定义一个依赖容器，用于存储和检索依赖项
export class DependencyContainer {
  private static dependencies = new Map<string, any>()

  public static register<T>(token: string, instance: T) {
    DependencyContainer.dependencies.set(token, instance)
  }

  public static resolve<T>(token: string): T {
    const dependency = DependencyContainer.dependencies.get(token)
    if (!dependency) {
      throw new Error(`【${token}】 不存在`)
    }
    return dependency
  }

  public static update<T>(token: string, newInstance: T) {
    DependencyContainer.dependencies.set(token, newInstance)
  }
}

// 用于注册依赖的装饰器
export function Injectable(token: string) {
  return function <T extends { new (...args: any[]): {} }>(constructor: T) {
    const instance = new constructor()
    // 如果注册时就需要为响应式
    // const reactiveInstance = createReactiveObject(instance, (key, value) => {
    //   // ...你的响应式逻辑
    // });
    // 注册响应式实例:
    // DependencyContainer.register(token, reactiveInstance);

    DependencyContainer.register(token, instance)
  }
}

// 负责监听值的变化并进行处理
function createReactiveObject<T extends object>(
  obj: T,
  onMutate: (target: T, key: PropertyKey, value: any) => void
): T {
  const handler = {
    get(target: T, key: PropertyKey, receiver: any) {
      const result = Reflect.get(target, key, receiver)
      return result
    },
    set(target: T, key: PropertyKey, value: any, receiver: any): boolean {
      const oldValue = target[key]
      const result = Reflect.set(target, key, value, receiver)
      if (oldValue !== value) {
        onMutate(target, key, value)
      }
      return result
    },
    deleteProperty(target: T, key: PropertyKey): boolean {
      if (key in target) {
        onMutate(target, key, undefined)
        return Reflect.deleteProperty(target, key)
      }
      return false
    }
  }

  return new Proxy(obj, handler)
}

// 用来注入依赖项的装饰器
export function Inject(token: string) {
  return function (target: any, propertyKey: string | symbol) {
    Object.defineProperty(target, propertyKey, {
      get: () => {
        let instance = DependencyContainer.resolve(token)
        if (typeof instance === 'object' && instance !== null) {
          instance = createReactiveObject(instance, (target, key, value) => {
            if (key === propertyKey) {
              DependencyContainer.update(token, value)
            }
          })
        }

        return instance
      },
      set: newValue => {
        DependencyContainer.update(token, newValue)
      },
      enumerable: true,
      configurable: true
    })
  }
}

export function getDependency(token: string): AppStore {
  return DependencyContainer.resolve<AppStore>(token)
}
